/*
 * Copyright 2019 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.util.internal;

import io.netty.util.Recycler;

/**
 * 轻量级对象池
 *
 * @param <T> 池中对象的类型
 */
public abstract class ObjectPool<T> {

    ObjectPool() {
    }

    /**
     * 创建一个新的 {@link ObjectPool}, 它将使用给定的 {@link ObjectCreator} 来创建应该被池化的 {@link Object}
     */
    public static <T> ObjectPool<T> newPool(final ObjectCreator<T> creator) {
        ObjectUtil.checkNotNull(creator, "creator");
        return new RecyclerObjectPool<T>(creator);
    }

    /**
     * 从 {@link ObjectPool} 获取一个 {@link Object}.
     * 如果没有池化的 {@link Object} 可供重用, 可能通过 {@link ObjectCreator#newObject(Handle)} 创建返回的对象.
     */
    public abstract T get();

    /**
     * 一旦该池化 {@link Object} 可以再次被重用, 它将用于通知 {@link ObjectPool}.
     *
     * @param <T>
     */
    public interface Handle<T> {

        /**
         * 如果可能, 回收该 {@link Object}, 使得可以被重新使用
         */
        void recycle(T self);
    }

    /**
     * 创建一个新对象, 它引用给定的 {@link Handle}, 一旦该对象可被重用, 调用 {@link Handle#recycle(Object)}
     *
     * @param <T> 池中对象的类型
     */
    public interface ObjectCreator<T> {

        /**
         * 创建并返回一个新的, 可用的, 稍后可通过 {@link Handle#recycle(Object)} 回收的 {@link Object}
         */
        T newObject(Handle<T> handle);
    }

    /**
     * 可回收的对象池
     *
     * @param <T> 池中对象的类型
     */
    private static final class RecyclerObjectPool<T> extends ObjectPool<T> {

        private final Recycler<T> recycler;

        RecyclerObjectPool(final ObjectCreator<T> creator) {
            recycler = new Recycler<T>() {
                @Override
                protected T newObject(Handle<T> handle) {
                    return creator.newObject(handle);
                }
            };
        }

        @Override
        public T get() {
            return recycler.get();
        }
    }
}
